home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / Games / xmemory-1.0 / xmemory.C < prev    next >
Encoding:
C/C++ Source or Header  |  1995-07-01  |  24.2 KB  |  1,090 lines

  1. /*
  2.  * Memory mit Scaleable Fonts und mehreren geoeffneten Bildschirmen
  3.  */
  4.  
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #if defined(sco)
  8. #include <string.h>
  9. #include <time.h>
  10. #else
  11. #include <strings.h>
  12. #endif
  13. #include <X11/Xlib.h>
  14. #include <X11/Xutil.h>
  15. #include <sys/time.h>
  16.  
  17. #define    _DoubleString
  18. #define    DoubleDepth
  19. #define    FlashSpeed    20
  20.  
  21. #define    MWidth(size)    (dwidth*size+nplayers*size+3*size)
  22. #define    MHeight(size)    (dheight*size+2*size)
  23. #define    MFieldX(x)        (((x)+1)*size+offx)
  24. #define    MFieldY(y)        (((y)+1)*size+offy)
  25. #define    SCol(x)            ((x)*size+(dwidth+2)*size+offx)
  26. #define    STop()            (size)
  27. #define    SRow(y)            (dheight*size+size-(y+1)*bsize)
  28.  
  29. static unsigned long current_time;
  30. static unsigned long get_current_time() {
  31. unsigned long ret;
  32. struct timeval    timeval;
  33. #if !defined(sco)
  34. extern int  gettimeofday (struct timeval *, struct timezone *);
  35. #endif
  36.  
  37.     gettimeofday( &timeval, NULL );
  38.     ret = timeval.tv_sec * 100 + timeval.tv_usec/10000;
  39.     return( ret );
  40. }
  41.  
  42. class Color {
  43.     friend class Port;
  44.  
  45. public:
  46.  
  47.     Color( class Port *, int color_id, char *color );
  48.     ~Color();
  49.  
  50.     GC                        gc_n;
  51.     unsigned long        pixel;
  52.     int                    color_id;
  53.     class Port            *p;
  54.  
  55. private:
  56.     static void brighten( XColor *chg, XColor *org, double percent );
  57.     Color                *next;
  58. };
  59.  
  60.  
  61. class Port {
  62.     friend class Tile;
  63.  
  64. public:
  65.     Port( char *disp_name, char *color, class Board &board );
  66.     ~Port();
  67.  
  68.     static void close_all()        { while(first)    delete first; }
  69.  
  70.     int empty_queue();
  71.     static int wait_event();
  72.  
  73.     void add_foreign_color( Port *first, char *color_name );
  74.     void add_color( int id, char *color );
  75.     void sub_color( int id );
  76.  
  77.     void redraw( int x, int y );
  78.     void redraw_score( int x );
  79.     void redraw( int x1, int y1, int x2, int y2 );
  80.     void draw_block( int p, int x, int y );
  81.  
  82.     void tile_redraw( int fid );
  83.     static void flush_all();
  84.  
  85.     int remove();
  86.     void selected( int x, int y );
  87.     unsigned long deselect( );
  88.  
  89.     Display    *display;
  90.     Screen    *screen;
  91.     Window    window;
  92.  
  93.     GC            gc_tile;
  94.     GC            gc_color_n( int id );
  95.  
  96.     void resize( int w, int h );
  97.     char *color_name;
  98.     int     my_id;
  99.  
  100.     static int nplayers;
  101.  
  102.     int    points;
  103.     int    Points( int id );
  104.  
  105. private:
  106.     class Tile    **tile;
  107.     class Tile    *blank;
  108.     class Tile    *empty;
  109.  
  110.     Port    *next;
  111.     Color    *colors;
  112.  
  113.     static Port *first;
  114.  
  115.     int size;
  116.     int bsize;
  117.     int offx, offy;
  118.     int width,height;
  119.  
  120.     static int    dsize;
  121.  
  122.     int        lock_count;
  123.     int        lock[2];
  124.     unsigned long lock_time;
  125.     unsigned long flash_time;
  126.  
  127.     class Board &board;
  128.  
  129.     static struct fd_set    readfds;
  130.     static int                nfds;
  131.  
  132.     Atom    WmProtocolsPropId, WmDeleteWindowPropId;
  133.  
  134. public:
  135.     static int    color_id;
  136.     static int    dwidth, dheight;
  137. };
  138.  
  139. ///////////////////////////////////////////////////////////////////////////////
  140.  
  141. class Tile {
  142.     friend Port;
  143.  
  144. public:
  145.     Tile( Port *p, XFontStruct    *font_info, int id );
  146.     ~Tile();
  147.  
  148.     enum shade {
  149.         light,
  150.         bg,
  151.         fg,
  152.         dark    
  153.     };
  154. private:
  155.     Display    *display;
  156.     Pixmap    pixmap;
  157.  
  158. };
  159.  
  160. Tile::Tile( Port *p, XFontStruct *font_info, int id )
  161. {
  162. XCharStruct *cs;
  163. char sign;
  164. int     offx, offy;
  165.  
  166. // check justification of sign
  167.     if ((id>=0)&&(id<=9))    sign = id+48;
  168.     if ((id>=10)&&(id<=35))    sign = id-10+65;
  169.     if ((id>=36)&&(id<=61))    sign = id-36+97;
  170.     if (id>61)                    sign = id-62+60;
  171.     if (id>67)                    sign = id-67+33;
  172.  
  173.     cs = &font_info->per_char[sign-font_info->min_char_or_byte2];
  174.     offx = (p->size-cs->width)/2+cs->lbearing;
  175.     offy = (p->size-font_info->ascent-font_info->descent)/2
  176.                 +font_info->ascent;
  177.  
  178. // create Pixmap
  179.     display = p->display;    // for automatic destruction
  180.  
  181.     pixmap = XCreatePixmap( display, RootWindowOfScreen(p->screen),
  182.                             p->size, p->size, DefaultDepthOfScreen(p->screen) );
  183.  
  184. // Background
  185.     XSetForeground( display, p->gc_tile, (id!=-1)?bg:fg );
  186.     XFillRectangle( display, pixmap, p->gc_tile, 0, 0, p->size, p->size );
  187.  
  188. // TopLeft highlight
  189.     XSetForeground( display, p->gc_tile, (id>=-1)?dark:light);
  190.     XDrawLine( display, pixmap, p->gc_tile, 0, 0, p->size-1, 0 );
  191.     XDrawLine( display, pixmap, p->gc_tile, 0, 0, 0, p->size-1 );
  192. #ifdef DoubleDepth
  193.     if (id==-2) {
  194.         XDrawLine( display, pixmap, p->gc_tile, 1, 1, p->size-2, 1 );
  195.         XDrawLine( display, pixmap, p->gc_tile, 1, 1, 1, p->size-2 );
  196.     }
  197. #endif
  198.     if (id>=0) {
  199. #ifdef DoubleString
  200.         XDrawString( display, pixmap, p->gc_tile, offx+2, offy+2, &sign, 1 );
  201. #endif
  202.         XDrawString( display, pixmap, p->gc_tile, offx+1, offy+1, &sign, 1 );
  203.     }
  204.  
  205. // BottomRight shade
  206.     XSetForeground( display, p->gc_tile, (id>=-1)?light:dark);
  207.     XDrawLine( display, pixmap, p->gc_tile, 0, p->size-1, p->size-1, p->size-1);
  208.     XDrawLine( display, pixmap, p->gc_tile, p->size-1, 0, p->size-1, p->size-1);
  209. #ifdef DoubleDepth
  210.     if (id==-2) {
  211.      XDrawLine( display, pixmap, p->gc_tile, 1, p->size-2, p->size-2, p->size-2);
  212.      XDrawLine( display, pixmap, p->gc_tile, p->size-2, 1, p->size-2, p->size-2);
  213.     }
  214. #endif
  215.     if (id>=0) {
  216. #ifdef DoubleString
  217.         XDrawString( display, pixmap, p->gc_tile, offx-2, offy-2, &sign, 1 );
  218. #endif
  219.         XDrawString( display, pixmap, p->gc_tile, offx-1, offy-1, &sign, 1 );
  220.     }
  221.  
  222. // Foreground
  223.     XSetForeground( display, p->gc_tile, fg );
  224.     if (id>=0)
  225.         XDrawString( display, pixmap, p->gc_tile, offx, offy, &sign, 1 );
  226. }
  227.  
  228. Tile::~Tile() {
  229.     XFreePixmap( display, pixmap );
  230. }
  231.  
  232. ///////////////////////////////////////////////////////////////////////////////
  233.  
  234. class Field {
  235. public:
  236.     void reset( int id )
  237.     { tile_id = id; lock_col = 0; locked=0; found=0; flash=0; gone=0; }
  238.  
  239.     int        tile_id;    // tile-index, used twice per board of course
  240.         unsigned lock_col    : 4;        // color_id
  241.         unsigned locked    : 1;        // geoeffnet
  242.         unsigned found        : 1;        // Treffer
  243.         unsigned flash        : 1;        // Highligh beim Blinken
  244.         unsigned gone        : 1;        // auf Stapel gelegt
  245. };
  246.  
  247. ///////////////////////////////////////////////////////////////////////////////
  248.  
  249. class Board {
  250. public:
  251.     Board( int width, int height );
  252.     ~Board();
  253.  
  254.     void reset();
  255.     void color_removed(int color_id);
  256.     int  tile_removed(int color_id);
  257.     Field    *field( int x, int y );
  258.     Field    *field( int fid );
  259.  
  260.     int                ntiles;
  261.     int                tiles_left;
  262.     unsigned long    finished;
  263.     int        dx, dy;        // dimension of board
  264.     Field    *f;
  265. };
  266.  
  267.  
  268. Board::Board( int width, int height )
  269. {
  270.     dx = width;
  271.     dy = height;
  272.     ntiles = dx * dy;
  273.     if (ntiles%2)    dx++;        // make even dimension
  274.     ntiles = dx * dy;
  275.     ntiles /= 2;
  276.  
  277.     f = new Field[2*ntiles];
  278. }
  279.  
  280. Board::~Board() {
  281.     delete f;
  282. }
  283.  
  284. void Board::reset() {
  285. int        i,j;
  286. Field    help;
  287.  
  288.     for (i=0;i<2*ntiles;i++)         f[i].reset(i/2);
  289.     for (i=0;i<2*ntiles;i++) {
  290.         j = rand()%(2*ntiles);
  291.         help = f[i];
  292.         f[i] = f[j];
  293.         f[j] = help;
  294.     }
  295.     tiles_left=ntiles;
  296.     finished=0;
  297. }
  298.  
  299. void Board::color_removed( int id ) {
  300. int i;
  301. int back=0;
  302.  
  303.     for (i=0;i<2*ntiles;i++) {
  304.         if (f[i].lock_col>=id) {
  305.             if (f[i].lock_col==id) {
  306.                 f[i].locked=0;
  307.                 f[i].found =0;
  308.                 f[i].flash =0;
  309.                 if (f[i].gone) {
  310.                     f[i].gone=0;
  311.                     back++;
  312.                 }
  313.             }
  314.             f[i].lock_col--;
  315.         }
  316.     }
  317.     tiles_left+=(back/2);
  318. }
  319.  
  320. int Board::tile_removed(int /* color_id */) {
  321.     if (--tiles_left)        return 0;
  322.     else {
  323.         finished = current_time;
  324.         return 1;
  325.     }
  326. }
  327.  
  328. Field *Board::field( int x, int y )
  329. {
  330.     if ((x<0)||(x>=dx)||(y<0)||(y>=dy))        return(0);
  331.     return( &f[x+y*dx] );
  332. }
  333.  
  334. Field *Board::field( int fid )
  335. {
  336.     return( field( fid%dx, fid/dx ) );
  337. }
  338.  
  339. //////////////////////////////////////////////////////////////////////////////
  340.  
  341. void Color::brighten( XColor *chg, XColor *org, double percent )
  342. {
  343.     if (percent<0) {
  344.         percent = 100+percent;
  345.         chg->red   = (unsigned short)(org->red*percent/100);
  346.         chg->green = (unsigned short)(org->green*percent/100);
  347.         chg->blue  = (unsigned short)(org->blue*percent/100);
  348.     }
  349.     else {
  350.         chg->red   = (unsigned short)((65536-org->red)*percent/100   + org->red);
  351.         chg->green = (unsigned short)((65536-org->green)*percent/100 + org->green);
  352.         chg->blue  = (unsigned short)((65536-org->blue)*percent/100  + org->blue);
  353.     }
  354. }
  355.  
  356. Color::Color( Port *p_in, int color_id, char *color_name ) :
  357.     p(p_in)
  358. {
  359. unsigned long plane_mask = ~0x7;
  360. XColor    def;
  361. XColor    chg[8];
  362.  
  363.     this->color_id = color_id;
  364.  
  365.     if (!XAllocColorCells( p->display, DefaultColormapOfScreen(p->screen),
  366.             True,            // contiguous
  367.             &plane_mask,    // plane-mask
  368.             2,                // number of planes
  369.             &pixel,            // field of pixels
  370.             1                // number of colors
  371.     )) {
  372.         fprintf( stderr, "out of colors\n" );
  373.         exit(0);
  374.     }
  375.  
  376. int i;
  377.     for (i=0;i<4;i++) {
  378.         char    colnam[40];
  379.         sprintf(colnam,"%s%d",color_name,i+1);
  380.         if (XLookupColor( p->display, DefaultColormapOfScreen(p->screen),
  381.                 colnam, &chg[i], &chg[i] ) )            break;
  382.     }
  383.     if (i<4) {
  384.         XLookupColor( p->display, DefaultColormapOfScreen(p->screen), color_name,
  385.                 &def, &def );
  386.         brighten(&chg[0],&def, 60.);
  387.         brighten(&chg[1],&def, 20.);
  388.         brighten(&chg[2],&def,-40.);
  389.         brighten(&chg[3],&def,-60.);
  390.     }
  391.  
  392.     for (i=0;i<4;i++) {
  393.         chg[i].pixel = pixel+i;
  394.         chg[i].flags = DoRed | DoGreen | DoBlue;
  395.     }
  396.  
  397.     XStoreColors( p->display, DefaultColormapOfScreen(p->screen), chg, 4 );
  398.  
  399.     gc_n = XCreateGC( p->display, RootWindowOfScreen(p->screen), 0L, NULL );
  400.     XSetPlaneMask( p->display, gc_n, ~0x3 );
  401.     XSetForeground( p->display, gc_n, pixel );
  402.  
  403.     next=0;
  404. }
  405.  
  406. Color::~Color() {
  407.     XFreeGC( p->display, gc_n );
  408.     if (next)    delete next;
  409. }
  410.  
  411. //////////////////////////////////////////////////////////////////////////////
  412.  
  413. Port *Port::first = 0;
  414. int  Port::color_id = 1;
  415. int  Port::dwidth  = 8;
  416. int  Port::dheight = 9;
  417. int  Port::dsize   = 44;
  418. int  Port::nplayers = 1;
  419.  
  420. struct fd_set Port::readfds;
  421. int Port::nfds = 0;
  422.  
  423.  
  424. Port::Port( char *disp_name, char *color, Board &board_in ) :
  425.     board(board_in)
  426. {
  427. char    dsp_nam[30];
  428. static int w=0;
  429. int i;
  430.  
  431.     strcpy( dsp_nam, disp_name );
  432.     if ((*disp_name)&&(!strchr(dsp_nam,':'))) {
  433.         strcat( dsp_nam, ":0" );
  434.     }
  435.  
  436. // open connection to display and create a window
  437.     display = XOpenDisplay( dsp_nam );
  438.     if (!display) {
  439.         fprintf( stderr, "can't open display '%s'.\n", dsp_nam );
  440.         return;
  441.     }
  442.     screen = DefaultScreenOfDisplay( display );
  443. //    XSynchronize(display,1);
  444.  
  445.     window = XCreateSimpleWindow( display, RootWindowOfScreen( screen ),
  446.                 0, 0, MWidth(dsize), MHeight(dsize),
  447.                 0, BlackPixelOfScreen(screen), WhitePixelOfScreen(screen) );
  448.     XStoreName( display, window, color );
  449.     XSelectInput( display, window, StructureNotifyMask|ExposureMask|ButtonPressMask );
  450.  
  451. XSizeHints    hints;
  452.     hints.flags = USPosition | USSize | PAspect;
  453.     hints.x = 100+(w%2)*(50+MWidth(dsize));
  454.     hints.y = 100+(w/2)*(50+MHeight(dsize));
  455.     hints.width  = MWidth(dsize);
  456.     hints.height = MHeight(dsize);
  457.     hints.min_aspect.x = hints.max_aspect.x = MWidth(dsize);
  458.     hints.min_aspect.y = hints.max_aspect.y = MHeight(dsize);
  459.     XSetNormalHints( display,window,&hints );
  460.     w++;
  461.  
  462.     this->width  = hints.width;
  463.     this->height = hints.height;
  464.  
  465. Atom atom = XInternAtom(display,"PmWindowType",True);
  466.     if (atom) {
  467.         char* win_type = "FGnormal";
  468.         XTextProperty prop;
  469.         XStringListToTextProperty (&win_type, 1, &prop);
  470.         XSetTextProperty (display, window, &prop, atom);
  471.         XFree((void*)prop.value);
  472.     }
  473.  
  474. //
  475. // Reaktion auf Destroy Message anmelden
  476. //
  477.     WmProtocolsPropId    = XInternAtom(display,"WM_PROTOCOLS",False);
  478.     WmDeleteWindowPropId = XInternAtom(display,"WM_DELETE_WINDOW",False);
  479.     XSetWMProtocols( display, window, &WmDeleteWindowPropId, 1 );
  480.  
  481. //
  482. // Fileselector merken
  483. //
  484.     if (!nfds)        FD_ZERO( &readfds );
  485.     FD_SET(  ConnectionNumber(display), &readfds  );
  486.     if (nfds<=ConnectionNumber(display))        nfds = ConnectionNumber(display)+1;
  487.  
  488.     tile = new Tile*[board.ntiles];
  489.     for (i=0;i<board.ntiles;i++)    tile[i]=0;
  490.     blank = 0;
  491.     empty = 0;
  492. // initialize graphic context for drawing tiles
  493.     gc_tile = XCreateGC( display, RootWindowOfScreen(screen), 0L, NULL );
  494.     XSetPlaneMask( display, gc_tile, 0x3 );
  495.  
  496. // initialise tiles
  497.     size=0;
  498.     resize( dsize*dwidth, dsize*dheight );
  499.  
  500. // exchange colors of ports
  501.     colors=0;
  502.     color_name = new char[strlen(color)+1];
  503.     strcpy( color_name, color );
  504.     my_id = color_id;
  505.     add_color( 0, "yellow" );
  506.     if (first)    add_foreign_color( first, color_name );
  507.     add_color( color_id, color_name );
  508.  
  509.     XSetWindowBackground( display, window, colors->pixel + 0x1 );
  510.     XMapRaised( display, window );
  511.  
  512. // connect to list of created displays
  513.     next = first;
  514.     first = this;
  515.  
  516.     color_id++;
  517.     lock_count = 0;
  518.     lock_time  = 0;
  519.     flash_time = 0;
  520.     lock[0] = lock[1] = -1;
  521.  
  522.     points = 0;
  523. }
  524.  
  525. void Port::add_foreign_color( Port *current, char *color_name ) {
  526.     current->add_color( color_id, color_name );
  527.     if (current->next)    add_foreign_color(current->next,color_name);
  528.     add_color( current->my_id, current->color_name );
  529. }
  530.  
  531.  
  532. void Port::sub_color( int id ) {
  533. Color    *current= colors;
  534. Color *mark;
  535.  
  536. //
  537. // Id dekrementieren
  538. //
  539.     while(current) {
  540.         if (current->color_id==id)        mark = current;
  541.         if (current->color_id>id)        current->color_id--;
  542.         current=current->next;
  543.     }
  544. //
  545. // Farbe ausketten
  546. //
  547.     if (mark==colors) {
  548.         colors = mark->next;
  549.     }
  550.     else {
  551.         current = colors;
  552.         while( current->next != mark )        current = current->next;
  553.         current->next = mark->next;
  554.     }
  555. //
  556. // Farbe loeschen
  557. //
  558.     mark->next    = 0;
  559.     delete mark;
  560.  
  561. //
  562. // neue Fensterdimension:
  563. //
  564.     offx = (width-MWidth(size))/2;
  565.     XClearWindow(display,window);
  566.     redraw(1,1,dwidth+nplayers+2,dheight+1);
  567. }
  568.  
  569. Port::~Port() {
  570.  
  571.     nplayers--;                                // Zahl der Spieler
  572.     board.color_removed(my_id);        // Farbe im Brett freigeben
  573.     color_id--;                                // Gesamtfarbenzaehler
  574. //
  575. // Farbe aus allen Ports austragen
  576. //
  577. Port    *current;
  578.  
  579.     current=first;
  580.     do {
  581.         if (current->my_id>my_id)     current->my_id--;
  582.         current = current->next;
  583.     } while(current);
  584.  
  585. //
  586. // Port ausketten
  587. //
  588.     if (this==first) {
  589.         first  = this->next;
  590.     }
  591.     else {
  592.         current = first;
  593.         while( current->next != this )        current = current->next;
  594.         current->next = this->next;
  595.     }
  596.  
  597. //
  598. // Farbe aus den Ports austragen
  599. //
  600.     for (current=first;current;current=current->next)
  601.                                             current->sub_color( my_id );
  602.  
  603.     for (int i=0;i<board.ntiles;i++) {
  604.         if (tile[i])        delete tile[i];
  605.     }
  606.     delete tile;
  607.     if (blank)    delete blank;
  608.     if (empty)    delete empty;
  609.     delete colors;
  610.     delete color_name;
  611.     XFreeGC( display, gc_tile );
  612.     XSync( display, 0 );
  613.     XCloseDisplay( display );
  614. }
  615.  
  616. void Port::add_color( int color_id, char *color_name )
  617. {
  618. Color *new_color;
  619.  
  620.     new_color = new Color( this, color_id, color_name );
  621. #if(1)
  622.     new_color->next = colors;
  623.     colors = new_color;
  624. #else
  625.     new_color->next = 0;
  626.     if (!colors)        colors = new_color;
  627.     else {
  628.         Color    *col = colors;
  629.         while( col->next )    col=col->next;
  630.         col->next=new_color;
  631.     }
  632. #endif
  633. }
  634.  
  635. int Port::empty_queue() {
  636. XEvent    event;
  637.  
  638.     // XSync( display, 0 );
  639.     while ( XEventsQueued( display, QueuedAfterFlush ) ) {
  640.         XNextEvent( display, &event );
  641.         switch( event.type ) {
  642.         case ButtonPress:
  643.         {
  644.             switch(event.xbutton.button) {
  645.             case 2:
  646.                 if (my_id==1)        return 1;
  647.  
  648.             default:
  649.             {    if (board.finished&¤t_time>board.finished+5000)    return 1;
  650.                 int x = (event.xbutton.x-offx-size)/size;
  651.                 int y = (event.xbutton.y-offy-size)/size;
  652.                 selected(x,y);
  653.             }
  654.             }
  655.             break;
  656.         }
  657.         case Expose:
  658.         {
  659.             int x1=(event.xexpose.x-offx)/size;
  660.             int y1=(event.xexpose.y-offy)/size;
  661.             int x2=(event.xexpose.x+event.xexpose.width-offx)/size;
  662.             int y2=(event.xexpose.y+event.xexpose.height-offy)/size;
  663.             redraw( x1, y1, x2, y2 );
  664.             break;
  665.         }
  666.         case ConfigureNotify:
  667.             resize( event.xconfigure.width, event.xconfigure.height );
  668.             break;
  669.  
  670.         case ClientMessage:
  671.             if (event.xclient.message_type == WmProtocolsPropId) {
  672.                 Atom data_atom = (Atom)event.xclient.data.l[0];
  673.                 if (data_atom == WmDeleteWindowPropId) {
  674.                     return -1;        // delete me !
  675.                 }
  676.             }
  677.         }
  678.     }
  679.     return 0;
  680. }
  681.  
  682. int Port::wait_event() {
  683. static unsigned long    next=0;
  684. int erg = 0;
  685.  
  686.     current_time = get_current_time();
  687.     if (!next)        next=current_time+100;
  688.  
  689.     if (current_time<next) {
  690.         struct timeval        timeout;
  691.         unsigned long    dist = next-current_time;
  692.         struct fd_set readfds_cp;
  693.  
  694.         memcpy( &readfds_cp, &readfds, sizeof(readfds) );
  695.         timeout.tv_sec  = dist / 100;
  696.         timeout.tv_usec = dist % 100;
  697. #if defined(sco)
  698.         select( nfds, &readfds_cp, 0, 0, &timeout );
  699. #else
  700.         select( nfds, (int*)&readfds_cp, 0, 0, &timeout );
  701. #endif
  702.         current_time = get_current_time();
  703.     }
  704.  
  705.     next = 0;
  706.     for( Port *current = first; current; current=current->next ) {
  707.         int delete_flag = current->empty_queue();
  708.  
  709.         if (delete_flag<0) {
  710.             delete current;    
  711.             if (first)    return erg+wait_event();
  712.             else            return 1;
  713.         }
  714.         else erg+=delete_flag;
  715.         long current_next = current->deselect();
  716.         if (current_next) {
  717.             if (!next||current_next<next)        next = current_next;
  718.         }
  719.     }
  720.     return erg;
  721. }
  722.  
  723. GC Port::gc_color_n( int id ) {
  724. Color    *current=colors;
  725. int i;
  726.  
  727.     for (i=color_id-1;i>id;i--)    current=current->next;
  728.  
  729.     return( current->gc_n );
  730. }
  731.  
  732. int Port::Points( int id ) {
  733. Port *current=first;
  734. int i;
  735.  
  736.     for (i=color_id-1;i>id;i--)    current=current->next;
  737.     return( current->points );
  738. }
  739.  
  740.  
  741. void Port::redraw( int x, int y )
  742. {
  743. Field *f= board.field(x,y);
  744.  
  745.     if (!f)        return;
  746.  
  747.     if (f->locked && !f->gone) {
  748.         XFillRectangle( display, window,
  749.             (f->flash)? gc_color_n(0) : gc_color_n(f->lock_col),
  750.             MFieldX(x), MFieldY(y), size, size );
  751.         XCopyArea( display, tile[f->tile_id]->pixmap, window, gc_tile,
  752.             0, 0, size, size, MFieldX(x), MFieldY(y) );
  753.     }
  754.     else {
  755. #if (1)
  756.         XCopyArea( display, ((f->found)?empty->pixmap:blank->pixmap),
  757.             window, gc_tile, 0, 0, size, size, MFieldX(x), MFieldY(y) );
  758. #else
  759.         XCopyArea( display, tile[f->tile_id]->pixmap, window, gc_tile,
  760.             0, 0, size, size, MFieldX(x), MFieldY(y) );
  761. #endif
  762.         XFillRectangle( display, window,
  763.             (f->found)?gc_color_n(f->lock_col):gc_color_n(my_id),
  764.             MFieldX(x), MFieldY(y), size, size );
  765.     }
  766. }
  767.  
  768. void Port::draw_block( int p, int x, int y ) {
  769.     XFillRectangle( display, window, gc_color_n(p+1), x, y, size, bsize );
  770.  
  771.     XSetForeground( display, gc_tile, Tile::bg );
  772.     XFillRectangle( display, window, gc_tile, x, y, size, bsize );
  773.  
  774.     XSetForeground( display, gc_tile, Tile::light );
  775.     XDrawLine( display, window, gc_tile, x, y, x+size-1, y );
  776.     XDrawLine( display, window, gc_tile, x, y, x, y+bsize-1 );
  777.  
  778.     XSetForeground( display, gc_tile, Tile::dark );
  779.     XDrawLine( display, window, gc_tile, x, y+bsize-1, x+size-1, y+bsize-1 );
  780.     XDrawLine( display, window, gc_tile, x+size-1, y, x+size-1, y+bsize-1 );
  781. }
  782.  
  783. void Port::redraw_score( int x )
  784. {
  785.     if (x>=nplayers)    return;
  786.  
  787.     XFillRectangle( display, window, gc_color_n(my_id),
  788.         SCol(x), STop(), size, dheight*size );
  789.     XSetForeground( display, gc_tile, Tile::fg);
  790.     XFillRectangle( display, window, gc_tile,
  791.         SCol(x), STop(), size, dheight*size );
  792.  
  793.     XSetForeground( display, gc_tile, Tile::dark);
  794.     XDrawLine( display, window, gc_tile,
  795.         SCol(x), STop(), SCol(x+1)-1, STop() );
  796.     XDrawLine( display, window, gc_tile,
  797.         SCol(x), STop(), SCol(x), STop()+dheight*size-1 );
  798.  
  799.     XSetForeground( display, gc_tile, Tile::light);
  800.     XDrawLine( display, window, gc_tile,
  801.         SCol(x), STop()+dheight*size-1, SCol(x+1)-1, STop()+dheight*size-1 );
  802.     XDrawLine( display, window, gc_tile,
  803.         SCol(x+1)-1, STop(), SCol(x+1)-1, STop()+dheight*size-1 );
  804.  
  805.     int height = Points(x+1);
  806.     for (int y=1;y<=height;y++) {
  807.         draw_block( x, SCol(x), SRow(y-1) );
  808.     }
  809.     XFlush( display );
  810. }
  811.  
  812. void Port::redraw( int x1, int y1, int x2, int y2 )
  813. {
  814. int x, y;
  815.  
  816.     if (x2>=dwidth+2) {
  817.         for (x=(x1>=dwidth+2)?x1:dwidth+2;x<=x2;x++) {
  818.             redraw_score(x-dwidth-2);
  819.         }
  820.         x2=dwidth+1;
  821.     }
  822.     if (x1>=dwidth+2)        x1=dwidth+1;
  823.  
  824.     for (x=x1;x<=x2;x++) {
  825.         for (y=y1;y<=y2;y++) {
  826.             redraw( x-1, y-1 );
  827.         }
  828.     }
  829. }
  830.  
  831. void Port::tile_redraw( int fid )
  832. {
  833. int x = fid%board.dx;
  834. int y = fid/board.dx;
  835.  
  836.     
  837.     for ( Port *current = first; current; current = current->next )
  838.     {    current->redraw( x, y );
  839.         XFlush( current->display );
  840.     }
  841. }
  842.  
  843. void Port::flush_all()
  844. {
  845.     for ( Port *current = first; current; current = current->next )
  846.         XFlush( current->display );
  847. }
  848.  
  849. int Port::remove() {
  850.     if ((lock_count>1)&&(board.field(lock[1])->found)) {
  851.         board.field(lock[1])->gone = 1;
  852.         tile_redraw( lock[1] );
  853.         board.field(lock[0])->gone = 1;
  854.         tile_redraw( lock[0] );
  855.         lock_count=0;
  856.         points+=2;
  857.  
  858.         for (Port *p=first;p;p=p->next) {
  859.             p->redraw_score(my_id-1);
  860.         }
  861.         board.tile_removed(my_id);
  862.         flash_time=0;
  863.         return 1;
  864.     }
  865.     else {
  866.         return 0;
  867.     }
  868. }
  869.  
  870. unsigned long Port::deselect()
  871. {
  872. unsigned long next = 0;
  873.  
  874.     if (flash_time&&flash_time<current_time) {
  875.         board.field(lock[0])->flash ^= 1;
  876.         board.field(lock[1])->flash ^= 1;
  877.         tile_redraw(lock[0]);
  878.         tile_redraw(lock[1]);
  879.         next=flash_time=current_time+FlashSpeed;
  880.     }
  881.     if (lock_time&¤t_time<lock_time)
  882.                                     return (!next||next>lock_time)?lock_time:next;
  883.  
  884.     if (lock_count>1) {
  885.         if (!remove()) {
  886.             board.field(lock[1])->locked = 0;
  887.             tile_redraw( lock[1] );
  888.         }
  889.     }
  890.     if (lock_count>0) {
  891.         board.field(lock[0])->locked = 0;
  892.         tile_redraw( lock[0] );
  893.     }
  894.     lock_count=0;
  895.     lock_time =0;
  896.  
  897.     return 0;
  898. }
  899.  
  900. void Port::selected( int x, int y )
  901. {
  902. int    fid;
  903. Field *f= board.field(x,y);
  904.  
  905.     if (!f)    return;
  906.  
  907. //printf( "Pos: (%d,%d), Tile: %d, Locks %d\n", x,y,f->tile_id,lock_count );
  908.     if (lock_count==2) {
  909.         if (!remove()) {
  910.     //        XBell( display, 100 );
  911.             return;
  912.         }
  913.     }
  914.  
  915.     fid = x+board.dx*y;
  916.  
  917. //printf("  fid: %d, removed: %d, lock_id: %d\n", fid, f->removed, f->lock_id );
  918.  
  919.     if (f->found)        return;
  920.     if (f->locked)    {
  921. #if (1)
  922.     //    XBell( display,100 );
  923.         return;
  924. #else
  925.         if (f->lock_col!=my_id){
  926.         }
  927.         else {
  928.             if (lock[0]==fid) {
  929.                 lock[0]=lock[1];
  930.             }
  931.             lock_count--;
  932.             f->locked=0;
  933.             tile_redraw( fid );
  934.             lock_time=current_time;
  935.             return;
  936.         }
  937. #endif
  938.     }
  939.  
  940.     f->lock_col = my_id;
  941.     f->locked   = 1;
  942.     lock[lock_count++] = fid;
  943.  
  944.     if (lock_count==2) {
  945.         if (board.field(lock[0])->tile_id==board.field(lock[1])->tile_id) {
  946.             board.field(lock[0])->found = 1;
  947.             board.field(lock[0])->flash = 1;
  948.             board.field(lock[1])->found = 1;
  949.             board.field(lock[1])->flash = 1;
  950.             tile_redraw( lock[0] );
  951.     //        tile_redraw( lock[1] );
  952.             flash_time = current_time+FlashSpeed;
  953.         }
  954.     }
  955.     tile_redraw( fid );
  956.     lock_time = current_time + ((lock_count==2)?100:300);
  957. }
  958.  
  959.  
  960. #define    ChFact    0.9
  961.  
  962. void Port::resize( int width, int height )
  963. {
  964. int    nsize;
  965. int  i;
  966. char font_name[BUFSIZ];
  967.  
  968.     nsize = width/(dwidth+nplayers+3);
  969.     if ( height/(dheight+2) < nsize )    nsize = height/(dheight+2);
  970.     offx = (width-MWidth(nsize))/2;
  971.     offy = (height-MHeight(nsize))/2;
  972.  
  973.     if (nsize==size)    return;
  974.     size=nsize;
  975.     bsize = size/dwidth;
  976.     this->width = width;
  977.     this->height = height;
  978. //    XResizeWindow( display, window, MWidth(size), MHeight(size) );
  979.  
  980.     // calculate screen resolution in dots per inch 25.4mm=1 inch
  981. int res_x = (int)(WidthOfScreen(screen)/(WidthMMOfScreen(screen)/25.4));
  982. int res_y = (int)(HeightOfScreen(screen)/(HeightMMOfScreen(screen)/25.4));
  983.  
  984.  
  985.     sprintf( font_name, "-agfa-cg times-bold-r-normal-92504-%d-*-%d-%d-p-*-hp-roman8", (int)(size*ChFact), res_x, res_y );
  986. XFontStruct *font_info = XLoadQueryFont( display, font_name );
  987.     if (!font_info) {
  988.         for (i=(int)(size*ChFact);i>0;i--) {
  989.             sprintf(font_name, "-adobe-courier-bold-r-normal-*-%d-*-%d-%d-*-*-*-*", i, res_x, res_y);
  990.             font_info = XLoadQueryFont( display, font_name );
  991.             if (font_info)        break;
  992.         }
  993.         if (i==0) {
  994.             fprintf( stderr, "unable to load font\n  %s\n", font_name );
  995.             fprintf( stderr, "is the font-server (/usr/bin/X11/fs) running ?\n" );
  996.             exit(0);
  997.         }
  998.     }
  999. // printf( "%s", font_name );
  1000.     XSetFont( display, gc_tile, font_info->fid );
  1001.  
  1002. #if (0)
  1003. printf( "Size:    %d\n", (int)(size*ChFact));
  1004. printf( "Descent: %d\n", font_info->descent );
  1005. printf( "Ascent:  %d\n", font_info->ascent );
  1006. printf( "Total:   %d\n", font_info->ascent+font_info->descent );
  1007. #endif
  1008.  
  1009.     for (i=0;i<board.ntiles;i++) {
  1010.         if ( tile[i] )        delete tile[i];
  1011.         tile[i] = new Tile( this, font_info, i );
  1012.     }
  1013.     if (blank)            delete blank;
  1014.     if (empty)            delete empty;
  1015.     empty = new Tile(this, font_info, -1);
  1016.     blank = new Tile(this, font_info, -2);
  1017.  
  1018.     XFreeFont( display, font_info );
  1019. }
  1020.  
  1021. //////////////////////////////////////////////////////////////////////////////
  1022.  
  1023. void usage() {
  1024.     printf("usage: memory [small|normal|big] [display/color]*\n" );
  1025.     printf("e.g.:  memory red hgr36:0.0/green hgr49:0.0/blue\n" );
  1026.     printf("The font-server has to be started at the selected hosts !!!\n" );
  1027.     exit(-1);
  1028. }
  1029.  
  1030. char    *def_col[] = {
  1031.     "red", "DodgerBlue", "gold", "DeepPink", "tomato", "OliveDrab",
  1032.     "aquamarine", "brown", "bisque", "sienna" };
  1033.  
  1034. main( int argc, char **argv )
  1035. {
  1036. int i;
  1037. long    timefield;
  1038. char    *color_name;
  1039. Board *board;
  1040.  
  1041.     time(&timefield);
  1042.     srand((int)timefield);
  1043.  
  1044.     Port::nplayers = (argc-1);
  1045.  
  1046.     if (argc<2)    usage();
  1047.     for (i=1;i<argc;i++) {
  1048.         if (!strcmp(argv[i],"small")) {
  1049.             Port::dwidth = 4;        Port::dheight = 5;
  1050.             Port::nplayers--;
  1051.         }
  1052.         else if (!strcmp(argv[i],"normal")) {
  1053.             Port::dwidth = 8;        Port::dheight = 9;
  1054.             Port::nplayers--;
  1055.         }
  1056.         else if (!strcmp(argv[i],"big")) {
  1057.             Port::dwidth = 11;    Port::dheight = 12;
  1058.             Port::nplayers--;
  1059.         }
  1060.         else break;
  1061.     }
  1062.  
  1063.     if (!Port::nplayers)    usage();
  1064.  
  1065.     board = new Board( Port::dwidth, Port::dheight );
  1066.  
  1067.     for (;i<argc;i++) {
  1068.         if ( color_name=strchr(argv[i],'/') ) {
  1069.             *color_name++ = '\0';
  1070.             new Port( argv[i], *color_name?color_name:def_col[Port::color_id-1], *board );
  1071.         }
  1072.         else {
  1073.             new Port( argv[i], def_col[Port::color_id-1], *board );
  1074.         }
  1075.     }
  1076.     board->reset();
  1077.  
  1078. #if (1)
  1079.     while(!Port::wait_event());
  1080. #else
  1081.     int    n=10;
  1082.     while(--n)                            Port::wait_event();
  1083. #endif
  1084.  
  1085.     Port::close_all();
  1086.     delete board;
  1087.  
  1088.     /* sleep(5); */
  1089. }
  1090.